import type {
  ILoginForm,
} from '@/api/login'
import type { IAuthLoginRes } from '@/api/types/login'
import { defineStore } from 'pinia'
import { computed, ref } from 'vue' // 修复：导入 computed
import {
  login as _login,
  logout as _logout,
  refreshToken as _refreshToken,
  wxLogin as _wxLogin,
  getWxCode,
} from '@/api/login'
import { isDoubleTokenRes, isSingleTokenRes } from '@/api/types/login'
import { isDoubleTokenMode } from '@/utils'
import { useUserStore } from './user'

// 初始化状态
const tokenInfoState = isDoubleTokenMode
  ? {
      accessToken: '',
      accessExpiresIn: 0,
      refreshToken: '',
      refreshExpiresIn: 0,
    }
  : {
      token: '',
      expiresIn: 0,
    }

export const useTokenStore = defineStore(
  'token',
  () => {
    // 定义用户信息
    const tokenInfo = ref<IAuthLoginRes>({ ...tokenInfoState })
    // 设置用户信息
    const setTokenInfo = (val: IAuthLoginRes) => {
      tokenInfo.value = val

      // 计算并存储过期时间
      const now = Date.now()
      console.log('=== setTokenInfo 调试 ===')
      console.log('setTokenInfo 输入:', val)
      console.log('isSingleTokenRes:', isSingleTokenRes(val))
      console.log('isDoubleTokenRes:', isDoubleTokenRes(val))

      if (isSingleTokenRes(val)) {
        // 单token模式
        const expireTime = now + val.expiresIn * 1000
        uni.setStorageSync('accessTokenExpireTime', expireTime)
        console.log('单token模式，设置过期时间:', expireTime)
      }
      else if (isDoubleTokenRes(val)) {
        // 双token模式
        const accessExpireTime = now + val.accessExpiresIn * 1000
        const refreshExpireTime = now + val.refreshExpiresIn * 1000
        uni.setStorageSync('accessTokenExpireTime', accessExpireTime)
        uni.setStorageSync('refreshTokenExpireTime', refreshExpireTime)
        console.log('双token模式，设置access过期时间:', accessExpireTime)
      }
      else {
        // 检查是否是嵌套结构 {user: {...}, tokens: {...}}
        if (val && typeof val === 'object' && 'tokens' in val) {
          const tokens = (val as any).tokens
          console.log('检测到嵌套tokens结构:', tokens)

          if (tokens && typeof tokens === 'object') {
            if ('accessToken' in tokens && 'refreshToken' in tokens) {
              // 嵌套的双token模式
              const accessExpireTime = now + (tokens.accessExpiresIn || 900) * 1000 // 默认15分钟
              const refreshExpireTime = now + (tokens.refreshExpiresIn || 604800) * 1000 // 默认7天
              uni.setStorageSync('accessTokenExpireTime', accessExpireTime)
              uni.setStorageSync('refreshTokenExpireTime', refreshExpireTime)
              console.log('嵌套双token模式，设置access过期时间:', accessExpireTime)
            }
            else if ('token' in tokens) {
              // 嵌套的单token模式
              const expireTime = now + (tokens.expiresIn || 7200) * 1000 // 默认2小时
              uni.setStorageSync('accessTokenExpireTime', expireTime)
              console.log('嵌套单token模式，设置过期时间:', expireTime)
            }
          }
        }
        else {
          console.log('未知的token结构，无法设置过期时间')
        }
      }
      console.log('==================')
    }

    /**
     * 判断token是否过期
     */
    const isTokenExpired = computed(() => {
      if (!tokenInfo.value) {
        console.log('isTokenExpired: tokenInfo.value不存在')
        return true
      }

      const now = Date.now()
      const expireTime = uni.getStorageSync('accessTokenExpireTime')

      console.log('=== Token过期检查 ===')
      console.log('当前时间戳:', now)
      console.log('token过期时间戳:', expireTime)
      console.log('剩余时间(ms):', expireTime ? expireTime - now : '无过期时间')
      console.log('是否过期:', expireTime ? now >= expireTime : '无过期时间，认为过期')
      console.log('==================')

      if (!expireTime)
        return true
      return now >= expireTime
    })

    /**
     * 判断refreshToken是否过期
     */
    const isRefreshTokenExpired = computed(() => {
      if (!isDoubleTokenMode)
        return true

      const now = Date.now()
      const refreshExpireTime = uni.getStorageSync('refreshTokenExpireTime')

      if (!refreshExpireTime)
        return true
      return now >= refreshExpireTime
    })

    /**
     * 登录成功后处理逻辑
     * @param tokenInfo 登录返回的token信息
     */
    async function _postLogin(tokenInfo: IAuthLoginRes) {
      setTokenInfo(tokenInfo)
      const userStore = useUserStore()
      await userStore.fetchUserInfo()
    }

    /**
     * 用户登录
     * 处理后端返回的登录响应格式：{code: 200, message: "创建成功", data: {user: {...}, tokens: {...}}}
     * @param loginForm 登录参数
     * @returns 登录结果
     */
    const login = async (loginForm: ILoginForm) => {
      try {
        const res = await _login(loginForm)
        console.log('普通登录-res: ', res)

        // 检查返回格式 - 处理新的API响应格式
        if (res && typeof res === 'object' && 'code' in res) {
          if (res.code !== 200) {
            // 登录失败，显示错误信息
            uni.showToast({
              title: res.message || '登录失败，请重试',
              icon: 'none',
              duration: 2000,
            })
            throw new Error(res.message || '登录失败')
          }
          else if (res.code === 200 && res.data) {
            // 登录成功，提取token和用户信息
            const { tokens, user } = res.data

            // 保存用户信息到user store
            if (user) {
              const userStore = useUserStore()
              userStore.setUserInfo({
                userId: user.id,
                username: user.username,
                nickname: user.nickname || user.username,
                avatar: user.avatar || '/static/images/default-avatar.png',
                // 可以添加其他需要的字段
                ...user,
              })
            }

            // 保存token信息
            if (tokens) {
              await _postLogin(tokens)
            }

            uni.showToast({
              title: '登录成功',
              icon: 'success',
            })
            return res.data
          }
        }
        // 处理直接返回 {user: {...}, tokens: {...}} 格式的响应
        else if (res && typeof res === 'object' && 'user' in res && 'tokens' in res) {
          const { user, tokens } = res as { user: any, tokens: IAuthLoginRes }

          // 保存用户信息到user store
          if (user) {
            const userStore = useUserStore()
            userStore.setUserInfo({
              userId: user.id,
              username: user.username,
              nickname: user.nickname || user.username,
              avatar: user.avatar || '/static/images/default-avatar.png',
              // 可以添加其他需要的字段
              ...user,
            })
          }

          // 保存token信息
          if (tokens) {
            await _postLogin(tokens)
          }

          uni.showToast({
            title: '登录成功',
            icon: 'success',
          })
          return res
        }
        // 兼容旧的返回格式
        else {
          await _postLogin(res)
          const userStore = useUserStore()
          await userStore.fetchUserInfo()
          uni.showToast({
            title: '登录成功',
            icon: 'success',
          })
          return res
        }
      }
      catch (error: any) {
        console.error('登录失败:', error)
        // 如果是业务错误（用户名密码错误），不重复显示toast
        if (error.message && !error.message.includes('网络') && !error.message.includes('timeout')) {
          // toast已经在上面显示了，这里不再重复
        }
        else {
          uni.showToast({
            title: '登录失败，请重试',
            icon: 'error',
          })
        }
        throw error
      }
    }

    /**
     * 微信登录
     * 有的时候后端会用一个接口返回token和用户信息，有的时候会分开2个接口，一个获取token，一个获取用户信息
     * （各有利弊，看业务场景和系统复杂度），这里使用2个接口返回的来模拟
     * @returns 登录结果
     */
    const wxLogin = async () => {
      try {
        // 获取微信小程序登录的code
        const code = await getWxCode()
        console.log('微信登录-code: ', code)
        const res = await _wxLogin(code)
        console.log('微信登录-res: ', res)
        await _postLogin(res)
        uni.showToast({
          title: '登录成功',
          icon: 'success',
        })
        return res
      }
      catch (error) {
        console.error('微信登录失败:', error)
        uni.showToast({
          title: '微信登录失败，请重试',
          icon: 'error',
        })
        throw error
      }
    }

    /**
     * 退出登录 并 删除用户信息
     */
    const logout = async () => {
      try {
        // TODO 实现自己的退出登录逻辑
        await _logout()
      }
      catch (error) {
        console.error('退出登录失败:', error)
      }
      finally {
        // 无论成功失败，都需要清除本地token信息
        // 清除存储的过期时间
        uni.removeStorageSync('accessTokenExpireTime')
        uni.removeStorageSync('refreshTokenExpireTime')
        console.log('退出登录-清除用户信息')
        tokenInfo.value = { ...tokenInfoState }
        uni.removeStorageSync('token')
        const userStore = useUserStore()
        userStore.clearUserInfo()
      }
    }

    /**
     * 刷新token
     * @returns 刷新结果
     */
    const refreshToken = async () => {
      if (!isDoubleTokenMode) {
        console.error('单token模式不支持刷新token')
        throw new Error('单token模式不支持刷新token')
      }

      try {
        // 从tokenInfo中获取refreshToken，支持不同的数据结构
        let refreshToken = ''

        // 检查是否是嵌套的tokens结构
        if (tokenInfo.value && typeof tokenInfo.value === 'object' && 'tokens' in tokenInfo.value) {
          refreshToken = (tokenInfo.value as any).tokens?.refreshToken || ''
        }
        // 检查是否是直接的token结构
        else if (tokenInfo.value && typeof tokenInfo.value === 'object' && 'refreshToken' in tokenInfo.value) {
          refreshToken = (tokenInfo.value as IDoubleTokenRes)?.refreshToken || ''
        }

        if (!refreshToken) {
          throw new Error('无效的refreshToken')
        }

        const res = await _refreshToken(refreshToken)
        console.log('刷新token-res: ', res)
        setTokenInfo(res)
        return res
      }
      catch (error) {
        console.error('刷新token失败:', error)
        throw error
      }
    }

    /**
     * 获取有效的token
     * 注意：在computed中不直接调用异步函数，只做状态判断
     * 实际的刷新操作应由调用方处理
     */
    const getValidToken = computed(() => {
      // token已过期，返回空
      if (isTokenExpired.value) {
        return ''
      }

      if (!isDoubleTokenMode) {
        return isSingleTokenRes(tokenInfo.value) ? tokenInfo.value.token : ''
      }
      else {
        // 从tokenInfo中获取accessToken，支持不同的数据结构
        if (tokenInfo.value && typeof tokenInfo.value === 'object' && 'tokens' in tokenInfo.value) {
          return (tokenInfo.value as any).tokens?.accessToken || ''
        }
        else if (tokenInfo.value && typeof tokenInfo.value === 'object' && 'accessToken' in tokenInfo.value) {
          return (tokenInfo.value as IDoubleTokenRes)?.accessToken || ''
        }
        return ''
      }
    })

    /**
     * 检查是否有登录信息（不考虑token是否过期）
     */
    const hasLoginInfo = computed(() => {
      if (!tokenInfo.value) {
        return false
      }
      if (isDoubleTokenMode) {
        // 检查是否有有效的accessToken，支持不同的数据结构
        if (tokenInfo.value && typeof tokenInfo.value === 'object' && 'tokens' in tokenInfo.value) {
          return !!((tokenInfo.value as any).tokens?.accessToken)
        }
        else if (tokenInfo.value && typeof tokenInfo.value === 'object' && 'accessToken' in tokenInfo.value) {
          return !!(tokenInfo.value as IDoubleTokenRes)?.accessToken
        }
        return false
      }
      else {
        return isSingleTokenRes(tokenInfo.value) && !!tokenInfo.value.token
      }
    })

    /**
     * 检查是否已登录且token有效
     */
    const hasValidLogin = computed(() => {
      console.log('hasValidLogin', hasLoginInfo.value, !isTokenExpired.value)
      return hasLoginInfo.value && !isTokenExpired.value
    })

    /**
     * 尝试获取有效的token，如果过期且可刷新，则刷新token
     * @returns 有效的token或空字符串
     */
    const tryGetValidToken = async (): Promise<string> => {
      if (!getValidToken.value && isDoubleTokenMode && !isRefreshTokenExpired.value) {
        try {
          await refreshToken()
          return getValidToken.value
        }
        catch (error) {
          console.error('尝试刷新token失败:', error)
          return ''
        }
      }
      return getValidToken.value
    }

    return {
      // 核心API方法
      login,
      wxLogin,
      logout,

      // 认证状态判断（最常用的）
      hasLogin: hasValidLogin,

      // 内部系统使用的方法
      refreshToken,
      tryGetValidToken,
      validToken: getValidToken,

      // 调试或特殊场景可能需要直接访问的信息
      tokenInfo,
      setTokenInfo,
    }
  },
  {
    // 添加持久化配置，确保刷新页面后token信息不丢失
    persist: true,
  },
)
